#include <stdlib.h>
#include <sys/socket.h>
#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include "stcp_server.h"
#include "../common/seg.h"
#include "../common/constants.h"
#include "../utils/concurrent.h"

int connection;
pthread_mutex_t mutex_list[MAX_TRANSPORT_CONNECTIONS];
server_tcb_t* tcb_list[MAX_TRANSPORT_CONNECTIONS];

/*面向应用层的接口*/

//
//
//  我们在下面提供了每个函数调用的原型定义和细节说明, 但这些只是指导性的, 你完全可以根据自己的想法来设计代码.
//
//  注意: 当实现这些函数时, 你需要考虑FSM中所有可能的状态, 这可以使用switch语句来实现.
//
//  目标: 你的任务就是设计并实现下面的函数原型.
//

// stcp服务器初始化
//
// 这个函数初始化TCB表, 将所有条目标记为NULL. 它还针对重叠网络TCP套接字描述符conn初始化一个STCP层的全局变量,
// 该变量作为sip_sendseg和sip_recvseg的输入参数. 最后, 这个函数启动seghandler线程来处理进入的STCP段.
// 服务器只有一个seghandler.
//

void stcp_server_init(int conn) {
	connection=conn;
	for(int i=0;i<MAX_TRANSPORT_CONNECTIONS;i++){
		tcb_list[i]=NULL;
		mutex_list[i]=(pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
	}
	pthread_t handler_tid;
	pthread_create(&handler_tid,NULL,seghandler,NULL);
  	return ;
}

// 创建服务器套接字
//
// 这个函数查找服务器TCB表以找到第一个NULL条目, 然后使用malloc()为该条目创建一个新的TCB条目.
// 该TCB中的所有字段都被初始化, 例如, TCB state被设置为CLOSED, 服务器端口被设置为函数调用参数server_port. 
// TCB表中条目的索引应作为服务器的新套接字ID被这个函数返回, 它用于标识服务器的连接. 
// 如果TCB表中没有条目可用, 这个函数返回-1.

int stcp_server_sock(unsigned int server_port) {
	int sockfd=0;
	for(;sockfd<MAX_TRANSPORT_CONNECTIONS;sockfd++){
		pthread_mutex_t* mutex=&mutex_list[sockfd];
		int successful_falg=0;
		pthread_mutex_lock(mutex);
		if(tcb_list[sockfd]==NULL){
			server_tcb_t* tcb=(server_tcb_t*)calloc(1,sizeof(server_tcb_t));
			tcb->server_portNum=server_port;
			tcb->state=CLOSED;
			tcb->next_seqNum=0;
			tcb->next_ackNum=0;
			tcb->recvBuf=(char*)calloc(RECEIVE_BUF_SIZE,sizeof(char));
			tcb->usedBufLen=0;
			tcb_list[sockfd]=tcb;
			successful_falg=1;
		}
		pthread_mutex_unlock(mutex);
		
		if(successful_falg)break;
	}

	if(sockfd==MAX_TRANSPORT_CONNECTIONS){
    	return -1;
  	}else {
   		return sockfd;
  }
}

// 接受来自STCP客户端的连接
//
// 这个函数使用sockfd获得TCB指针, 并将连接的state转换为LISTENING. 它然后进入忙等待(busy wait)直到TCB状态转换为CONNECTED 
// (当收到SYN时, seghandler会进行状态的转换). 该函数在一个无穷循环中等待TCB的state转换为CONNECTED,  
// 当发生了转换时, 该函数返回1. 你可以使用不同的方法来实现这种阻塞等待.
//


int stcp_server_accept(int sockfd) {
	server_tcb_t* tcb=NULL;
	pthread_mutex_t* mutex=&mutex_list[sockfd];

	pthread_mutex_lock(mutex);
	if((tcb=tcb_list[sockfd])!=NULL){
		tcb->state=LISTENING;
		pthread_mutex_unlock(mutex);
	}else{
		pthread_mutex_unlock(mutex);
		return -1;
	}

	while(1){
		int is_connected=0;
		pthread_mutex_lock(mutex);
		if((tcb=tcb_list[sockfd])!=NULL){
			if(tcb->state==CONNECTED)
				is_connected=1;
			pthread_mutex_unlock(mutex);
		}else{
			pthread_mutex_unlock(mutex);
			return -1;
		}
		if(is_connected)break;
		usleep((ACCEPT_POLLING_INTERVAL/1000));	
	}
	return 1;
}

// 接收来自STCP客户端的数据. 请回忆STCP使用的是单向传输, 数据从客户端发送到服务器端.
// 信号/控制信息(如SYN, SYNACK等)则是双向传递. 这个函数每隔RECVBUF_ROLLING_INTERVAL时间
// 就查询接收缓冲区, 直到等待的数据到达, 它然后存储数据并返回1. 如果这个函数失败, 则返回-1.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int stcp_server_recv(int sockfd, void* buf, unsigned int length){
	pthread_mutex_t* mutex=&mutex_list[sockfd];
	if(length>RECEIVE_BUF_SIZE)return -1;
	int err_flag=0;
	int wait_flag=1;
	while(wait_flag){
		pthread_mutex_lock(mutex);
		server_tcb_t* tcb=tcb_list[sockfd];
		if(tcb==NULL || tcb->state!=CONNECTED){
			err_flag=1;
		}else if(tcb->usedBufLen>=length){
			memcpy(buf,tcb->recvBuf,length);
			char* buf_ptr = tcb->recvBuf+length;
			tcb->usedBufLen-=length;
			memcpy(tcb->recvBuf,buf_ptr,tcb->usedBufLen);
			wait_flag=0;
		}
		pthread_mutex_unlock(mutex);
		if(err_flag)return -1;
		usleep(RECVBUF_POLLING_INTERVAL/1000);
	}
  	return 0;
}

// 关闭STCP服务器
//
// 这个函数调用free()释放TCB条目. 它将该条目标记为NULL, 成功时(即位于正确的状态)返回1,
// 失败时(即位于错误的状态)返回-1.
//

int stcp_server_close(int sockfd) {
	pthread_mutex_t* mutex=&mutex_list[sockfd];
	pthread_mutex_lock(mutex);

	server_tcb_t* tcb=tcb_list[sockfd];
	int ret=-1;
	if(tcb!=NULL){
		if(tcb->state==CLOSED){
			ret=1;
		}
		free(tcb->recvBuf);
		free(tcb);
		tcb_list[sockfd]=NULL;
	}

	pthread_mutex_unlock(mutex);
	return ret;
}

// 处理进入段的线程
//
// 这是由stcp_server_init()启动的线程. 它处理所有来自客户端的进入数据. seghandler被设计为一个调用sip_recvseg()的无穷循环, 
// 如果sip_recvseg()失败, 则说明重叠网络连接已关闭, 线程将终止. 根据STCP段到达时连接所处的状态, 可以采取不同的动作.
// 请查看服务端FSM以了解更多细节.
//


void server_closed(server_tcb_t* tcb,seg_t* seg,int nodeID){
	return ;
}

void ack_syn(server_tcb_t* tcb, seg_t* seg){
	if(verify_syn_seg(seg,tcb->client_portNum,tcb->server_portNum)){
		tcb->state=CONNECTED;
		seg_t* synack_seg=create_synack_seg(tcb->server_portNum,tcb->client_portNum);
		sip_sendseg(connection,tcb->client_nodeID,synack_seg);
		free(synack_seg);
	}
}

void server_listening(server_tcb_t* tcb,seg_t* seg,int nodeID){
	switch(seg->header.type){
		case SYN:{
			tcb->client_portNum=seg->header.src_port;
			tcb->client_nodeID=nodeID;
			ack_syn(tcb,seg);
			break;
		}
		default:{
			break;
		}
	}
}

void ack_fin(server_tcb_t* tcb, seg_t* seg){
	if(verify_fin_seg(seg,tcb->client_portNum,tcb->server_portNum,
								tcb->next_ackNum,tcb->next_seqNum)){
		seg_t* finack_seg=create_finack_seg(tcb->server_portNum,
						  tcb->client_portNum,tcb->next_seqNum,tcb->next_ackNum);
		sip_sendseg(connection,tcb->client_nodeID,finack_seg);
		free(finack_seg);
	}
}

void* closewait_timer_thread(void* args){
	u_int64_t sockfd=(u_int64_t)args;
	pthread_t self_tid=pthread_self();
	pthread_detach(self_tid);

	clock_t start,end;
	start=clock();
	double duration=0;

	while(duration<CLOSEWAIT_TIMEOUT){
		end=clock();
		duration=((double)(end-start)/CLOCKS_PER_SEC);
	}
	pthread_mutex_t *mutex = &mutex_list[sockfd];
	pthread_mutex_lock(mutex);
	server_tcb_t* tcb=tcb_list[sockfd];
	if(tcb!=NULL){
		tcb->state=CLOSED;
		tcb->usedBufLen=0;
	}
	pthread_mutex_unlock(mutex);
	return NULL;
}

seg_t* create_dataack_seg(unsigned int src_port,unsigned int dest_port,unsigned int seq_num,unsigned int ack_num){
	seg_t* dataack_seg=(seg_t*)calloc(1,sizeof(seg_t));
	dataack_seg->header.src_port=src_port;
	dataack_seg->header.dest_port=dest_port;
	dataack_seg->header.seq_num=seq_num;
	dataack_seg->header.ack_num=ack_num;
	dataack_seg->header.length=0;
	dataack_seg->header.type=DATAACK;
	return dataack_seg;
}

void ack_data(server_tcb_t*tcb,seg_t* seg,int nodeID){
	//仅仅确认当前需要的段
	if(tcb->state!=CONNECTED || 
		seg->header.dest_port!=tcb->server_portNum ||
		seg->header.src_port!=tcb->client_portNum || 
		seg->header.seq_num!=tcb->next_ackNum)
		return ;

	if(seg->header.seq_num==tcb->next_ackNum){
		if(tcb->usedBufLen + seg->header.length > RECEIVE_BUF_SIZE){
			return ;
		}else{
			memcpy((tcb->recvBuf+tcb->usedBufLen),seg->data,seg->header.length);
			tcb->usedBufLen += seg->header.length;
			tcb->next_ackNum += seg->header.length;
		}
	}
	seg_t* dataack_seg=create_dataack_seg(tcb->server_portNum,tcb->client_portNum,
										  tcb->next_seqNum,tcb->next_ackNum);
	sip_sendseg(connection,nodeID,dataack_seg);
	free(dataack_seg);
}

void server_connected(server_tcb_t* tcb,seg_t* seg,int nodeID){
	switch(seg->header.type){
		case SYN:{
			ack_syn(tcb,seg);
			break;
		}
		case FIN:{
			ack_fin(tcb,seg);
			tcb->state=CLOSEWAIT;

			u_int64_t sockfd=-1;
			for(int i=0;i<MAX_TRANSPORT_CONNECTIONS;i++){
				if(tcb_list[i]==tcb){
					sockfd=i;
					break;
				}
			}
			pthread_t closewait_tid;
			pthread_create(&closewait_tid,NULL,closewait_timer_thread,(void*)sockfd);
			break;
		}
		case DATA:{
			concurrent_printf_reminder("expected segnum:%d,actual segnum:%d\n",
							   tcb->next_ackNum,seg->header.seq_num);
			ack_data(tcb,seg,nodeID);
		}
		default:{
			break;
		}
	}
}

void server_closewait(server_tcb_t* tcb,seg_t* seg,int nodeID){
	switch(seg->header.type){
		case FIN:{
			ack_fin(tcb,seg);
			break;
		}
		default:{
			break;
		}
	}
}

void handle_seg(int sockfd,seg_t* seg,int nodeID){
	pthread_mutex_t* mutex=&mutex_list[sockfd];
	pthread_mutex_lock(mutex);

	server_tcb_t* tcb=tcb_list[sockfd];
	if(tcb!=NULL){
		switch(tcb->state){
			case CLOSED:{
				server_closed(tcb,seg,nodeID);
				break;
			}
			case LISTENING:{
				server_listening(tcb,seg,nodeID);
				break;
			}
			case CONNECTED:{
				server_connected(tcb,seg,nodeID);
				break;
			}
			case CLOSEWAIT:{
				server_closewait(tcb,seg,nodeID);
				break;
			}
			default :{
				concurrent_printf_warning("handle_seg:unknown server state!\n");
				break;
			}
		}
	}
	pthread_mutex_unlock(mutex);
}

int get_sockfd_by_port(unsigned int server_port){
	int sockfd=-1;
	for(int i=0;i<MAX_TRANSPORT_CONNECTIONS;i++){
		pthread_mutex_t *mutex=&mutex_list[i];
		pthread_mutex_lock(mutex);
		server_tcb_t* tcb=NULL;
		if((tcb=tcb_list[i])!=NULL &&  
			tcb->server_portNum==server_port){
			sockfd=i;
		}
		pthread_mutex_unlock(mutex);
		if(sockfd!=-1)break;
	}
	return sockfd;
}

void *seghandler(void* arg) {
	pthread_t self_tid=pthread_self();
	pthread_detach(self_tid);

	while(1){
		seg_t* seg=(seg_t*)calloc(1,sizeof(seg_t));
		int nodeID;
		int choice=sip_recvseg(connection,&nodeID,seg);
		if(choice == 1){
			free(seg);
			continue;
		}
		if(choice == -1){
			free(seg);
			break;
		}

		int sockfd = get_sockfd_by_port(seg->header.dest_port);
		if(sockfd == -1){
			concurrent_printf_warning("server seghandler:target tcb can't be found!\n");
		}else{
			handle_seg(sockfd,seg,nodeID);
		}
		free(seg);
	}
	return NULL;
}